import zhinst.utils  # create API object
import numpy as np
from abc import ABC


def singleton(class_):
    class SingletonFactory(ABC):
        instance = None

        def __new__(cls, *args, **kwargs):
            if not cls.instance:
                cls.instance = class_(*args, **kwargs)
            return cls.instance
    SingletonFactory.register(class_)
    return SingletonFactory


@singleton
class ziDAQ(object):
    """singleton class for zurich daq
    """
    def __init__(self, connectivity=8004, labone_ip='localhost'):
        # connectivity must be 8004 for zurish instruments
        self.daq = zhinst.ziPython.ziDAQServer(labone_ip, connectivity, 6)
        self.dev_id = 'dev8334'
        self.awg_index = 0

    def set_port(self, dev_id, awg_index):
        self.dev_id = dev_id
        self.awg_index = awg_index

    def get_port(self):
        return self.dev_id, self.awg_index

    def dc_offset(self, dc_I=0.0, dc_Q=0.0):
        self.daq.setDouble('/{:s}/sigouts/{:d}/offset'.format(
            self.dev_id, self.awg_index * 2), dc_I)
        self.daq.setDouble('/{:s}/sigouts/{:d}/offset'.format(
            self.dev_id, self.awg_index*2+1), dc_Q)

    def open_sine_pulse(self):
        self.daq.setInt('/{:s}/sines/{:d}/enables/0'.format(
            self.dev_id, self.awg_index*2), 1)
        self.daq.setInt('/{:s}/sines/{:d}/enables/1'.format(
            self.dev_id, self.awg_index*2+1), 1)

    def close_sine_pulse(self):
        self.daq.setInt('/{:s}/sines/{:d}/enables/0'.format(
            self.dev_id, self.awg_index*2), 0)
        self.daq.setInt('/{:s}/sines/{:d}/enables/1'.format(
            self.dev_id, self.awg_index*2+1), 0)

    def sine_freq(self, freq=10e6):
        self.daq.setDouble('/{:s}/oscs/{:d}/freq'.format(
            self.dev_id, self.awg_index), freq)

    def sine_amp(self, amp_I=0.5, amp_Q=0.5):
        self.daq.setDouble('/{:s}/sines/{:d}/amplitudes/0'.format(
            self.dev_id, self.awg_index*2), amp_I)
        self.daq.setDouble('/{:s}/sines/{:d}/amplitudes/1'.format(
            self.dev_id, self.awg_index*2+1), amp_Q)

    def shift_phase(self, phi_I=0, phi_Q=-90):
        # shift phase for sine pulse
        self.daq.setDouble('/{:s}/sines/{:d}/phaseshift'.format(
            self.dev_id, self.awg_index*2), phi_I)
        self.daq.setDouble('/{:s}/sines/{:d}/phaseshift'.format(
            self.dev_id, self.awg_index*2+1), phi_Q)
